﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.CodeDom;
using System.Xml;
using System.ComponentModel;

namespace MetadataBasedConfigArch.ExpressionWeb.ExpressionBuilders
{
    [System.Web.Compilation.ExpressionEditor("MetadataBasedConfigArch.ExpressionWeb.ExpressionBuilders.XmlExpressionEditor"), System.Web.Compilation.ExpressionPrefix("Xml")]
    public class XmlExpressionBuilder:System.Web.Compilation.ExpressionBuilder
    {
        #region Override Methods

        public override System.CodeDom.CodeExpression GetCodeExpression(System.Web.UI.BoundPropertyEntry entry, object parsedData, System.Web.Compilation.ExpressionBuilderContext context)
        {
            if ((entry.DeclaringType == null) || (entry.PropertyInfo == null))
            {
                return new CodeMethodInvokeExpression(new CodeTypeReferenceExpression(GetType()), "GetXmlValue", new CodePrimitiveExpression(entry.Expression.Trim()));
            }

            return new CodeMethodInvokeExpression(new CodeTypeReferenceExpression(GetType()), "GetXmlValue", new CodePrimitiveExpression(entry.Expression.Trim()),new CodeTypeOfExpression(entry.DeclaringType), new CodePrimitiveExpression(entry.PropertyInfo.Name));
        }

        public override bool SupportsEvaluate
        {
            get
            {
                return true;
            }
        }

        public override object EvaluateExpression(object target, System.Web.UI.BoundPropertyEntry entry, object parsedData, System.Web.Compilation.ExpressionBuilderContext context)
        {
            if ((entry.DeclaringType == null) || (entry.PropertyInfo == null))
            {
                return new CodeMethodInvokeExpression(new CodeTypeReferenceExpression(GetType()), "GetXmlValue", new CodePrimitiveExpression(entry.Expression.Trim()));
            }

            return new CodeMethodInvokeExpression(new CodeTypeReferenceExpression(GetType()), "GetXmlValue", new CodePrimitiveExpression(entry.Expression.Trim()), new CodeTypeOfExpression(entry.DeclaringType), new CodePrimitiveExpression(entry.PropertyInfo.Name));
        }

        public override object ParseExpression(string expression, Type propertyType, System.Web.Compilation.ExpressionBuilderContext context)
        {
            //return base.ParseExpression(expression, propertyType, context);
            return expression.Split(",".ToArray());
        }

        #endregion 

        #region Static Methods

        public static string GetXmlValue(string key)
        {
            string[] keys = key.Split(",".ToArray());
            string xmlDocFileName = HttpContext.Current.Server.MapPath("~/Data/" + keys[0]);
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(xmlDocFileName);
            XmlNode node = xmlDoc.SelectSingleNode(keys[1]);
            if (node != null)
            {
                return node.InnerText;
            }
            return String.Empty;
        }

        public static object GetXmlValue(string key, Type declareType, string propertyName)
        {
            PropertyDescriptor propertyDescriptor = TypeDescriptor.GetProperties(declareType).Find(propertyName, false);
            if (propertyDescriptor == null)
            {
                throw new InvalidOperationException("Not find the property!");
            }

            string value = GetXmlValue(key);
            if (!String.IsNullOrEmpty(value) && propertyDescriptor.Converter != null)
            {
                return propertyDescriptor.Converter.ConvertFromString(value);
            }
            return null;
        }

        #endregion
    }
}